#include "ParticleSystem.hpp"

#include "gl.hpp"

#include "Global.hpp"
#include "ResourcesManager.hpp"
#include "Helper.hpp"


//velocity generation Funktion
Vector3f RandomVec()
{
	return (Vector3f(	rand()%1000/1000.f-.5f,
						rand()%1000/1000.f-.5f,
						rand()%1000/1000.f-.5f).normalize());
}											
											
ParticleSystem::ParticleSystem(Vector3f Origin, std::string Texture):
m_Origin(Origin),
m_Color(1, 1, 1),
m_StartAlpha(1),
m_EndAlpha(0)
{
	m_Texture=ResMan.GetTexture(ResourceDir+Texture);

	m_ParticleLifetime=8.0f;
}

void ParticleSystem::onTick(float Time)
{
	for(s_Particle& pat : m_Particles)
	{
		UpdateParticle(pat, Time);
		pat.Position+=pat.Velocity*Time;
		pat.Velocity+=m_Gravity*Time;
		pat.Age+=Time;
	}

	//delete to old particles
	//we know that all old particles are at the beginning of the list
	//so we just need pop_front
	while(!m_Particles.empty() && m_Particles.front().Age>m_ParticleLifetime)
		m_Particles.pop_front();

	//create new particles:

}

void ParticleSystem::onRender()
{
	//---------calculate Camera Axis:------------
	
	float ViewMatrix[16], Inv[16];
	glGetFloatv(GL_MODELVIEW_MATRIX, ViewMatrix);
	InvertMatrix(ViewMatrix, Inv);
	
	Vector3f CamX(Inv[0], Inv[1], Inv[2]);
	Vector3f CamY(Inv[4], Inv[5], Inv[6]);
	Vector3f CamZ(Inv[8], Inv[9], Inv[10]);

	//_____________________________


	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_ALPHA_TEST);
	glDisable(GL_LIGHTING);
	glDepthMask(false);
	glBindTexture(GL_TEXTURE_2D, m_Texture);
	
	glBegin(GL_QUADS);

	for(s_Particle& pat : m_Particles)
	{
		glColor4f(m_Color.x, m_Color.y, m_Color.z,
			m_StartAlpha+(m_EndAlpha-m_StartAlpha)*(pat.Age/m_ParticleLifetime));

		Vector3f pos=m_Origin+pat.Position;

		Vector3f t;

		glTexCoord2f(1, 1);
		t=pos+( CamX+CamY)*pat.Size;
		glVertex3fv(&t.x);
		
		glTexCoord2f(0, 1);
		t=pos+(-CamX+CamY)*pat.Size;
		glVertex3fv(&t.x);
		
		glTexCoord2f(0, 0);
		t=pos+(-CamX-CamY)*pat.Size;
		glVertex3fv(&t.x);
		
		glTexCoord2f(1, 0);
		t=pos+( CamX-CamY)*pat.Size;
		glVertex3fv(&t.x);

	}

	glEnd();
	
	glDepthMask(true);
	glColor4f(1, 1, 1, 1);
	glDisable(GL_BLEND);
	glEnable(GL_LIGHTING);
}


//-------------- smoke particles ------------

SmokeParticle::SmokeParticle(Vector3f Origin):
ParticleSystem(Origin, "Particles/Rauch.png")
{
	m_StartAlpha=0.2f;
	
	for(unsigned int i=0; i<80; ++i)
	{
		m_Particles.push_back(GenerateParticle());
	}
}

s_Particle SmokeParticle::GenerateParticle()
{
	s_Particle pat;
	pat.Size=0.8f;
	pat.Position=RandomVec()/2;

	float Speed=rand()%100/100.0f*2;
	pat.Velocity=RandomVec()*Speed;

	return pat;
}


void SmokeParticle::UpdateParticle(s_Particle& Pat, float Time)
{
	Pat.Size+=Time/2;
}
//__________________________________________



//-------------- spark particles ------------

SparksParticle::SparksParticle(Vector3f Origin, Vector3f Color):
ParticleSystem(Origin, "Particles/Sparkle.png")
{
	m_StartAlpha = 1;
	m_EndAlpha = 1;

	m_Color=Color;
	m_Gravity=Vector3f(0, 0, -8);

	m_ParticleLifetime = 4.0f;

	for(unsigned int i=0; i<25; ++i)
	{
		m_Particles.push_back(GenerateParticle());
	}
}

s_Particle SparksParticle::GenerateParticle()
{
	s_Particle pat;
	pat.Size=0.1f;

	pat.Position=RandomVec();
	pat.Position.z=(pat.Position.z+1)/2;

	pat.Velocity=RandomVec();
	pat.Velocity=pat.Velocity.normalize()*(1+rand()%100/100.f*4.f);
	pat.Velocity.z+=3;

	return pat;
}


void SparksParticle::UpdateParticle(s_Particle& Pat, float Time)
{
}
//__________________________________________



//-------------- fire particles ------------

FireParticle::FireParticle(Vector3f Origin, Vector3f Color, float Size):
ParticleSystem(Origin, "Particles/Fire.png"),
	m_FireEndSize(Size)
{
	m_StartAlpha=0.6f;
	m_Color=Color;
	m_ParticleLifetime=2.0f;
	
	for(unsigned int i=0; i<20; ++i)
	{
		m_Particles.push_back(GenerateParticle());
	}
}

s_Particle FireParticle::GenerateParticle()
{
	s_Particle pat;
	pat.Size=0.0f;
	pat.Position=RandomVec()*0.5;

	float Speed = rand()%100/100.0f*0.5f;
	pat.Velocity=RandomVec()*Speed;

	return pat;
}


void FireParticle::UpdateParticle(s_Particle& Pat, float Time)
{
	Pat.Size=Pat.Age/m_ParticleLifetime*m_FireEndSize;;
}
//__________________________________________